package com.tongqin.distributed;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

import java.util.List;
import java.util.UUID;

/**
 * @author yuantongqin
 * @date 2018/8/9 下午4:43
 */
public class RedisLock {

    /**
     * 获取锁
     */
    public String getLock(String key, int timeout) {
        try {
            Jedis jedis = RedisManager.getJedis();
            String value = UUID.randomUUID().toString();
            long end = System.currentTimeMillis() + timeout;
            while (System.currentTimeMillis() < end) {//阻塞
                String set = jedis.set(key, value, "NX", "PX", timeout);
                if("OK".equalsIgnoreCase(set)){
                    return value;
                }
                if (jedis.setnx(key, value) == 1) {
                    //如果在这里设置超时时间，如果宕机了超时时间设置不进去
                    jedis.expire(key,timeout);
                    return value;
                }

                if(jedis.ttl(key)==-1){//检测过期时间，在设置过期时间
                    jedis.expire(key,timeout);
                }

                Thread.sleep(1000);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }


    /**
     * 释放锁
     */
    public boolean releaseLock(String key,String value) {
        try {
            Jedis jedis = RedisManager.getJedis();
            while (true){
                jedis.watch(key);//watch机制
                if(value.equals(jedis.get(key))){//判断获得锁的线程与当前redis中存在锁是同一个
                    Transaction transaction = jedis.multi();
                    transaction.del(key);//事务执行的密令
                    List<Object> exec = transaction.exec();//事务最终执行
                    for (Object x : exec) {//让他变成一个阻塞的操作
                        if(x == null){
                            continue;
                        }
                        return true;//如果锁都存在
                    }

                }
                break;
            }
            jedis.unwatch();
            return true;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }


    public static void main(String[] args) {
        RedisLock lock = new RedisLock();
        String lock1 = lock.getLock("lock:aaa", 2000);
        if(lock1 != null){
            System.out.println("获取锁成功");
        }
        String lock2 = lock.getLock("lock:aaa", 2000);
        System.out.println(lock2);

    }
}
